home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™94 / Miscellaneous / Randy Thelen / ThreadedBrot / Lib / Window.cp < prev   
Encoding:
Text File  |  1994-06-26  |  18.2 KB  |  751 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Window.cp
  3.  
  4.     Contains:    Implementation of TWindow, a base class which provides a
  5.                 framework for building way-cool windows which even John
  6.                 Sullivan would be happy with. Floating windows and “smart
  7.                 zooming” algorithms are based on code samples provided by
  8.                 Dean Yu.
  9.                 
  10.     Written by: Dave Falkenburg
  11.  
  12.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  13.  
  14.     Change History (most recent first):
  15.     
  16.     To Do:        Create invisible, and bug free showing and hiding windows
  17.                 Window positioning methods (getters and setters)
  18.                 Display Manager support: AdjustWindowForNewScreen?
  19.                 Changes to support AEObject model
  20.  */
  21.  
  22. #include <Types.h>
  23. #include <Windows.h>
  24. #include <Errors.h>
  25. #include <Script.h>        //    for GetMBarHeight()
  26. #include <LowMem.h>        //    for LMGetWindowList()
  27.  
  28. #include "AppLib.h"
  29. #include "Window.h"
  30. #include <Threads.h>
  31.  
  32. const short            kFloatingWindowKind        = 1000;
  33. const short            kNormalWindowKind        = 1001;
  34. const WindowPtr     kNoFloatingWindows        = (WindowPtr) -1;
  35.  
  36. const short            kScreenEdgeSlop            = 4;
  37. const short            kSpaceForFinderIcons    = 64;
  38. const short            kMinimumTitleBarHeight    = 21;
  39. const short            kMinimumWindowSize        = 32;
  40.  
  41. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  42.  
  43. static void            FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect, GDHandle * theBestDevice);
  44. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  45.  
  46. struct    CalcWindowAreaDeviceLoopUserData
  47.     {
  48.     GDHandle    fScreenWithLargestPartOfWindow;
  49.     long        fLargestArea;
  50.     Rect        fWindowBounds;
  51.     };
  52.  
  53.  
  54. TWindow::TWindow()
  55.     {
  56.     }
  57.  
  58. TWindow::~TWindow()
  59.     {
  60.     }
  61.  
  62. void
  63. TWindow::CreateWindow(Boolean isFloating)
  64.     {
  65.     WindowPtr    behindWindow,oldFrontMostWindow;
  66.     
  67.     if (isFloating)
  68.         {
  69.         behindWindow = (WindowPtr) -1;
  70.         oldFrontMostWindow = FrontWindow();
  71.         }
  72.     else
  73.         {
  74.         behindWindow = LastFloatingWindow();
  75.         
  76.         if (behindWindow == kNoFloatingWindows)
  77.             oldFrontMostWindow = nil;
  78.         else
  79.             oldFrontMostWindow = (WindowPtr) ((WindowPeek) behindWindow)->nextWindow;
  80.         }
  81.             
  82.     fWindow = MakeNewWindow(behindWindow);
  83.  
  84.     if (fWindow)
  85.         {
  86.         SetWRefCon(fWindow,(long) this);
  87.  
  88.         fIsFloatingWindow = isFloating;
  89.         fIsVisible = true;                    //    should be visibleFlag
  90.         
  91.         ((WindowPeek) fWindow)->windowKind = kNormalWindowKind;
  92.  
  93.         if (isFloating)
  94.             {
  95.             ((WindowPeek) fWindow)->windowKind = kFloatingWindowKind;
  96.             
  97.             //    make sure the other window stays hilited
  98.  
  99.             if (oldFrontMostWindow)
  100.                 HiliteAndActivateWindow(oldFrontMostWindow,true);
  101.             }
  102.         else
  103.             {
  104.             ((WindowPeek) fWindow)->windowKind = kNormalWindowKind;
  105.  
  106.             //    unhighlight the old front window
  107.  
  108.             if (oldFrontMostWindow)
  109.                 HiliteAndActivateWindow(oldFrontMostWindow,false);
  110.  
  111.             //    hilite the new window…
  112.             
  113.             HiliteAndActivateWindow(fWindow,true);
  114.             }
  115.         }
  116.     }
  117.  
  118.  
  119. void
  120. TWindow::AdjustCursor(EventRecord * /* anEvent */)
  121.     {
  122.     }
  123.  
  124. void
  125. TWindow::Idle(EventRecord * /* anEvent */)
  126.     {
  127.     YieldToAnyThread();
  128.     }
  129.     
  130. void
  131. TWindow::Activate(Boolean /* activating */)
  132.     {
  133.     }
  134.     
  135. void
  136. TWindow::Draw(void)
  137.     {
  138.     }
  139.     
  140. void
  141. TWindow::Click(EventRecord * /* anEvent */)
  142.     {
  143.     }
  144.     
  145. void
  146. TWindow::KeyDown(EventRecord * /* anEvent */)
  147.     {
  148.     }
  149.  
  150.  
  151. void
  152. TWindow::Select(void)
  153.     {
  154.     WindowPtr    currentFrontWindow;
  155.     
  156.     if (fIsFloatingWindow)
  157.         currentFrontWindow = FrontWindow();
  158.     else
  159.         currentFrontWindow = FrontNonFloatingWindow();
  160.  
  161.     if (currentFrontWindow != fWindow)
  162.         {
  163.         if (fIsFloatingWindow)
  164.             BringToFront(fWindow);
  165.         else
  166.             {
  167.             WindowPtr    lastFloater = LastFloatingWindow();
  168.  
  169.             //    If there are no floating windows,
  170.             //    just call SelectWindow like the good ol’ days
  171.  
  172.             if (lastFloater == kNoFloatingWindows)
  173.                 SelectWindow(fWindow);
  174.             else
  175.                 {
  176.                 // Deactivate the window currently in front.
  177.  
  178.                 HiliteAndActivateWindow(currentFrontWindow,false);
  179.     
  180.                 // Bring it behind the last floating window and activate it.
  181.                 // Note that Inside Mac 1 states that you need to call PaintOne() and CalcVis() on a
  182.                 // window if you are using SendBehind() to bring it closer to the front.  With System 7,
  183.                 // this is no longer necessary.
  184.  
  185.                 SendBehind(fWindow,lastFloater);
  186.                 HiliteAndActivateWindow(fWindow,true);
  187.                 }
  188.             }
  189.         }
  190.     }
  191.  
  192.  
  193. void
  194. TWindow::Drag(Point startPoint)
  195.     {
  196.     GrafPtr        savePort;
  197.     KeyMap        theKeyMap;
  198.     Boolean        commandKeyDown = false;
  199.     RgnHandle    draggingRegion;
  200.     long        dragResult;
  201.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  202.     
  203.     if (WaitMouseUp())        //    de-bounce?
  204.         {
  205.         // Set up the Window Manager port.
  206.     
  207.         GetPort(&savePort);
  208.         SetPort(gWindowManagerPort);
  209.         SetClip(GetGrayRgn());
  210.  
  211.         // Check to see if the command key is down.
  212.     
  213.         GetKeys(theKeyMap);
  214.         commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  215.         
  216.         if (commandKeyDown)
  217.             {
  218.             //    We’re not going to change window ordering,
  219.             //    so make sure that we don’t drag in front of
  220.             //    other windows which may be in front of ours.
  221.  
  222.             ClipAbove(windowAsWindowPeek);
  223.             }
  224.         else if (!fIsFloatingWindow)
  225.             {
  226.             //    We’re dragging a normal window, so make sure
  227.             //    that we don’t drag in front of any floating
  228.             //    windows.
  229.  
  230.             ClipAbove((WindowPeek) FrontNonFloatingWindow());
  231.             }
  232.         
  233.         //    Drag an outline of the window around the desktop.
  234.         //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  235.  
  236.         draggingRegion = NewRgn();
  237.         CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
  238.         dragResult = DragGrayRgn(draggingRegion, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  239.         DisposeRgn(draggingRegion);
  240.  
  241.     
  242.         SetPort(savePort);    //    Get back to old port
  243.  
  244.         if ((dragResult != 0) && (dragResult != 0x80008000))
  245.             {
  246.             short         newHorizontalPosition,newVerticalPosition;
  247.  
  248.             newHorizontalPosition = (short) (**windowAsWindowPeek->contRgn).rgnBBox.left + (dragResult & 0xFFFF);
  249.             newVerticalPosition = (short) (**windowAsWindowPeek->contRgn).rgnBBox.top + (dragResult >> 16);
  250.             
  251.             MoveWindow(fWindow,newHorizontalPosition,newVerticalPosition,false);
  252.             }
  253.         }
  254.  
  255.     if (!commandKeyDown)
  256.         Select();
  257.     }
  258.  
  259.  
  260. void
  261. TWindow::Grow(Point startPoint)
  262.     {
  263.     GrafPtr    oldPort;
  264.     long    newSize;
  265.     Rect    oldWindowRect,resizeLimits;
  266.     
  267.     GetPort(&oldPort);
  268.     
  269.     GetWindowSizeLimits(&resizeLimits);
  270.     newSize = GrowWindow(fWindow,startPoint,&resizeLimits);
  271.     if (newSize)
  272.         {
  273.         oldWindowRect = fWindow->portRect;
  274.         SizeWindow(fWindow,(short) newSize,(short) (newSize >> 16),true);
  275.         SetPort(fWindow);
  276.         AdjustForNewWindowSize(&oldWindowRect,&fWindow->portRect);
  277.         }
  278.     
  279.     SetPort(oldPort);
  280.     }
  281.  
  282.  
  283. void
  284. TWindow::Zoom(short zoomState)
  285.     {
  286.     GrafPtr        oldPort;
  287.     FontInfo    systemFontInfo;
  288.     short        titleBarHeight;
  289.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  290.     short        amountOffscreen;
  291.     WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  292.     GDHandle    bestDevice;
  293.     
  294.     GetPort(&oldPort);
  295.  
  296.     //    Figure out the height of the title bar so we can properly position
  297.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  298.     //
  299.     //    This probably isn’t the best thing to do: A better way might be 
  300.     //    to diff the structure and content region rectangles?
  301.  
  302.     SetPort(gWindowManagerPort);
  303.     GetFontInfo(&systemFontInfo);
  304.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  305.     if ((titleBarHeight % 2) == 1)
  306.         titleBarHeight--;
  307.     if (titleBarHeight < kMinimumTitleBarHeight)
  308.         titleBarHeight = kMinimumTitleBarHeight;
  309.  
  310.  
  311.     //    Only do the voodoo magic if we are really “zooming” the window.
  312.  
  313.     if (zoomState == inZoomOut)
  314.         {
  315.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  316.         bestScreenRect.top += titleBarHeight;
  317.  
  318.         GetPerfectWindowSize(&perfectWindowRect);
  319.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  320.  
  321.         //    Take the zero-pined perfect window size and move it to
  322.         //    the top left of the    window’s content region.
  323.  
  324.         OffsetRect(&perfectWindowRect,(**windowAsWindowPeek->contRgn).rgnBBox.left,
  325.                                       (**windowAsWindowPeek->contRgn).rgnBBox.top);
  326.  
  327.         
  328.         //    Does perfectWindowRect fit completely on the best screen?
  329.         
  330.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  331.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  332.             {
  333.             //    SectRect sez perfectWindowRect doesn’t completely fit
  334.             //    on the screen, so bump the window so that more of it fits.
  335.  
  336.             //    Make sure that the left edge of perfectWindowRect is forced
  337.             //    onto the best screen.  This is in case we are bumping
  338.             //    the window to the right.
  339.  
  340.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  341.             if (amountOffscreen > 0)
  342.                 {
  343.                 perfectWindowRect.left += amountOffscreen;
  344.                 perfectWindowRect.right += amountOffscreen;
  345.                 }
  346.  
  347.             //    Make sure that the left edge of perfectWindowRect is forced
  348.             //    onto the best screen.  This is in case we are bumping
  349.             //    the window downward to a new screen.
  350.     
  351.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  352.             if (amountOffscreen > 0)
  353.                 {
  354.                 perfectWindowRect.top += amountOffscreen;
  355.                 perfectWindowRect.bottom += amountOffscreen;
  356.                 }
  357.  
  358.             //    If right edge of window falls off the screen,
  359.             //        Move window to the left until the right edge IS on the screen
  360.             //        OR the left edge is at bestScreenRect.left
  361.  
  362.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  363.             if (amountOffscreen > 0)
  364.                 {
  365.                 //    Are we going to push the left edge offscreen? If so, change the
  366.                 //    offset so we move the window all the way over to the left.
  367.                 
  368.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  369.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  370.  
  371.                 perfectWindowRect.left -= amountOffscreen;
  372.                 perfectWindowRect.right -= amountOffscreen;
  373.                 }
  374.  
  375.             //    If bottom edge of window falls off the screen,
  376.             //        Move window to up until the bottom edge IS on the screen
  377.             //        OR the top edge is at bestScreenRect.top
  378.  
  379.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  380.             if (amountOffscreen > 0)
  381.                 {
  382.                 //    Are we going to push the top edge offscreen? If so, change the
  383.                 //    offset so we move the window just to the top.
  384.                 
  385.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  386.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  387.  
  388.                 perfectWindowRect.top -= amountOffscreen;
  389.                 perfectWindowRect.bottom -= amountOffscreen;
  390.                 }
  391.  
  392.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  393.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  394.                 {
  395.                 //    The edges of the window still fall offscreen,
  396.                 //    so make the window smaller until it fits.
  397.                 
  398.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  399.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  400.  
  401.                 //    If the right edge is still falling off,
  402.                 //        save space for Finder’s disk icons as well.
  403.  
  404.                 if (perfectWindowRect.right > bestScreenRect.right)
  405.                     {
  406.                     perfectWindowRect.right = bestScreenRect.right;
  407.                     
  408.                     //    If we were on the main screen, leave room for Finder icons, too.
  409.                     
  410.                     if (bestDevice == GetMainDevice())
  411.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  412.                     }
  413.                 }
  414.             }
  415.  
  416.         //    Stash our new rectangle inside of the Window’s dataHandle
  417.         //    so that ZoomWindow does the right thing.
  418.         
  419.         (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  420.         }
  421.  
  422.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  423.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  424.     
  425.     SetPort(fWindow);
  426.  
  427.     Rect    oldWindowRect = fWindow->portRect;
  428.     
  429.     ZoomWindow(fWindow,zoomState,false);
  430.     AdjustForNewWindowSize(&oldWindowRect,&fWindow->portRect);
  431.  
  432.     SetPort(oldPort);
  433.     }
  434.  
  435.  
  436. void
  437. TWindow::ShowOrHide(Boolean showFlag)
  438.     {
  439.     //    This wrapper for ShowHide allows us to correctly
  440.     //    show or hide floating windows behind the back of the
  441.     //    rest of the application.
  442.     
  443.     fIsVisible = showFlag;
  444.     ShowHide(fWindow,showFlag);
  445.     }
  446.     
  447.  
  448. Boolean
  449. TWindow::EventFilter(EventRecord * /* theEvent */)
  450.     {
  451.     return (false);
  452.     }
  453.     
  454.  
  455. void
  456. TWindow::GetPerfectWindowSize(Rect *perfectSize)
  457.     {
  458.     *perfectSize = qd.screenBits.bounds;
  459.     }
  460.  
  461. void
  462. TWindow::GetWindowSizeLimits(Rect *limits)
  463.     {
  464.     limits->top = limits->left = kMinimumWindowSize;
  465.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  466.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  467.     }
  468.  
  469. void
  470. TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  471.     {
  472.     }
  473.  
  474.  
  475. Boolean
  476. TWindow::IsVisible(void)
  477.     {
  478.     return fIsVisible;
  479.     }
  480.  
  481.  
  482. Boolean
  483. TWindow::CanClose(void)
  484.     {
  485.     return(true);
  486.     }
  487.  
  488. Boolean
  489. TWindow::Close(void)
  490.     {
  491.     WindowPtr    newFrontWindow = nil;
  492.     
  493.     if (FrontNonFloatingWindow() == fWindow)
  494.         newFrontWindow = (WindowPtr) ((WindowPeek) fWindow)->nextWindow;
  495.  
  496.     DisposeWindow(fWindow);
  497.  
  498.     if (newFrontWindow)
  499.         HiliteAndActivateWindow(newFrontWindow,true);
  500.     return(true);
  501.     }
  502.  
  503.  
  504. Boolean
  505. TWindow::DeleteAfterClose(void)
  506.     {
  507.     return(true);
  508.     }
  509.  
  510. Boolean
  511. TWindow::CanEdit(void)
  512.     {
  513.     return(false);
  514.     }
  515.  
  516. void
  517. TWindow::DoEditMenu(short /* menuCode */)
  518.     {
  519.     }
  520.  
  521.  
  522. OSErr
  523. TWindow::HandleDrag(DragTrackingMessage /* dragMessage */, DragReference /* theDrag */)
  524.     {
  525.     return(noErr);
  526.     }
  527.  
  528.     
  529. OSErr
  530. TWindow::HandleDrop(DragReference /* theDrag */)
  531.     {
  532.     return(noErr);
  533.     }
  534.  
  535.  
  536. ///////////////////////////////////////////////////////////////////////////
  537. //
  538. //    Utility Functions used for floating windows
  539. //
  540.  
  541. TWindow *
  542. GetWindowObject(WindowPtr aWindow)
  543.     {
  544.     short    wKind;
  545.     
  546.     if (aWindow != nil)
  547.         {
  548.         wKind = ((WindowPeek) aWindow)->windowKind;
  549.  
  550.         if (wKind >= userKind)
  551.             {
  552.             //    All windowKinds >= userKind are based upon TWindow
  553.  
  554.             return (TWindow *) GetWRefCon(aWindow);
  555.             }
  556.         }
  557.     return (TWindow *) nil;
  558.     }
  559.  
  560.  
  561. WindowPtr
  562. LastFloatingWindow(void)
  563.     {
  564.     WindowPeek    aWindow = (WindowPeek) FrontWindow();
  565.     WindowPtr    lastFloater = (WindowPtr) kNoFloatingWindows;
  566.     
  567.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  568.         {
  569.         if (aWindow->visible)
  570.             lastFloater = (WindowPtr) aWindow;
  571.  
  572.         aWindow = (WindowPeek) aWindow->nextWindow;
  573.         }
  574.     return(lastFloater);
  575.     }
  576.  
  577.  
  578. WindowPtr
  579. FrontNonFloatingWindow(void)
  580.     {
  581.     WindowPeek    aWindow = (WindowPeek) LMGetWindowList();
  582.  
  583.     //    Skip over floating windows
  584.         
  585.     while (aWindow && (aWindow->windowKind == kFloatingWindowKind))
  586.         aWindow = (WindowPeek) aWindow->nextWindow;
  587.  
  588.     //    Skip over invisible, but otherwise normal windows
  589.     
  590.     while (aWindow && (aWindow->visible == 0))
  591.         aWindow = (WindowPeek) aWindow->nextWindow;
  592.         
  593.     return (WindowPtr) aWindow;
  594.     }
  595.  
  596.  
  597. void
  598. HiliteAndActivateWindow(WindowPtr aWindow,Boolean active)
  599.     {
  600.     GrafPtr        oldPort;
  601.     TWindow    *    wobj = GetWindowObject(aWindow);
  602.     
  603.     if (aWindow)
  604.         {
  605.         HiliteWindow(aWindow,active);
  606.  
  607.         if (wobj != nil)
  608.             {
  609.             GetPort(&oldPort);
  610.             SetPort(aWindow);
  611.             wobj->Activate(active);
  612.             SetPort(oldPort);
  613.             }    
  614.         }
  615.     }
  616.  
  617. void
  618. SuspendResumeWindows(Boolean resuming)
  619.     {
  620.     //    When we suspend/resume, hide/show all the visible floaters
  621.     
  622.     HiliteShowHideFloatingWindows(resuming,true);
  623.     }
  624.  
  625. void
  626. HiliteWindowsForModalDialog(Boolean hiliting)
  627.     {
  628.     //    When we display a modal dialog, we need to unhighlight
  629.     //    all visible floaters. We also need to re-hilite them
  630.     //    afterwards.
  631.     
  632.     HiliteShowHideFloatingWindows(hiliting,false);
  633.     }
  634.  
  635. void
  636. HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
  637.     {
  638.     WindowPeek    aWindow;
  639.     TWindow *    wobj;
  640.     
  641.     HiliteAndActivateWindow(FrontNonFloatingWindow(),hiliting);
  642.  
  643.     aWindow = LMGetWindowList();
  644.     while (aWindow && aWindow->windowKind == kFloatingWindowKind)
  645.         {
  646.         wobj = GetWindowObject((WindowPtr) aWindow);
  647.         
  648.         //    If we are hiding or showing, only hide/show windows
  649.         //    that were visible to begin with.
  650.          
  651.         if (dohiding && (wobj != nil) && ((wobj->IsVisible()) || (!hiliting)))
  652.             ShowHide((WindowPtr) aWindow,hiliting);
  653.  
  654.         //    All floaters are hilited if any floater is hilited
  655.  
  656.         HiliteWindow((WindowPtr) aWindow,hiliting);
  657.         aWindow = (WindowPeek) aWindow->nextWindow;
  658.         }
  659.     }
  660.  
  661.  
  662. ///////////////////////////////////////////////////////////////////////////
  663. //
  664. //    Routines used for dealing with windows and multiple screens
  665. //
  666.  
  667. pascal void
  668. CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  669.     {
  670.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  671.     long                                windowAreaOnThisScreen;
  672.     Rect                                windowRectOnThisScreen;
  673.     
  674.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  675.  
  676.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  677.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  678.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  679.  
  680.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  681.         {
  682.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  683.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  684.         }
  685.     }
  686.  
  687.  
  688. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  689.  
  690.  
  691. void
  692. FindScreenRectWithLargestPartOfWindow(WindowPtr aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  693.     {
  694.     RgnHandle                            copyOfWindowStrucRgn;
  695.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  696.  
  697.     //    Use DeviceLoop to find out what GDevice contains the largest
  698.     //    portion of the supplied window.
  699.     //
  700.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  701.     //            the window strucRgn, not contRgn.
  702.  
  703.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  704.     deviceLoopData.fLargestArea = -1;
  705.     deviceLoopData.fWindowBounds = (**(((WindowPeek) aWindow)->contRgn)).rgnBBox;
  706.     
  707.     copyOfWindowStrucRgn = NewRgn();
  708.     CopyRgn(((WindowPeek) aWindow)->strucRgn,copyOfWindowStrucRgn);
  709.  
  710.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  711.  
  712.     DisposeRgn(copyOfWindowStrucRgn);
  713.     
  714.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  715.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  716.  
  717.     //    Leave some space around the edges of the screen so window look good, AND
  718.     //    if the best device is the main screen, leave space for the Menubar
  719.     
  720.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  721.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  722.         theBestScreenRect->top += GetMBarHeight();
  723.     }
  724.  
  725.  
  726. ///////////////////////////////////////////////////////////////////////////
  727. //
  728. //    Drag Manager callback routines which dispatch to a window’s method
  729. //
  730.  
  731. pascal OSErr    CallWindowDragTrackingHandler(DragTrackingMessage dragMessage,WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  732.     {
  733.     TWindow *wobj = GetWindowObject(theWindow);
  734.     
  735.     if (wobj)
  736.         return(wobj->HandleDrag(dragMessage,theDrag));
  737.     else
  738.         return(noErr);
  739.     }
  740.  
  741.     
  742. pascal OSErr    CallWindowDragReceiveHandler(WindowPtr theWindow,void * /* refCon */,DragReference theDrag)
  743.     {
  744.     TWindow *wobj = GetWindowObject(theWindow);
  745.     
  746.     if (wobj)
  747.         return(wobj->HandleDrop(theDrag));
  748.     else
  749.         return(noErr);
  750.     }
  751.